home *** CD-ROM | disk | FTP | other *** search
- //-----------------------------------------------------------------------------
- // File: flexwnd.cpp
- //
- // Desc: CFlexWnd is a generic class that encapsulates the functionalities
- // of a window. All other window classes are derived from CFlexWnd.
- //
- // Child classes can have different behavior by overriding the
- // overridable message handlers (OnXXX members).
- //
- // Copyright (C) Microsoft Corporation. All Rights Reserved.
- //-----------------------------------------------------------------------------
-
- #include "common.hpp"
- #include "typeinfo.h"
-
- BOOL CFlexWnd::sm_bWndClassRegistered = FALSE;
- WNDCLASSEX CFlexWnd::sm_WndClass;
- LPCTSTR CFlexWnd::sm_tszWndClassName = _T("Microsoft.CFlexWnd.WndClassName");
- HINSTANCE CFlexWnd::sm_hInstance = NULL;
- CFlexToolTip CFlexWnd::s_ToolTip; // Shared tooltip window object
- DWORD CFlexWnd::s_dwLastMouseMove; // Last GetTickCount() that we have a WM_MOUSEMOVE
- HWND CFlexWnd::s_hWndLastMouseMove; // Last window handle of WM_MOUSEMOVE
- LPARAM CFlexWnd::s_PointLastMouseMove; // Last point of WM_MOUSEMOVE
- HWND CFlexWnd::s_CurrPageHwnd; // For unhighlighting callouts when a click is made outside of a callout
-
-
- int NewID()
- {
- static int i = 0;
- return ++i;
- }
-
- CFlexWnd::CFlexWnd() : m_nID(NewID()),
- m_hWnd(m_privhWnd), m_privhWnd(NULL), m_hRenderInto(NULL),
- m_bIsDialog(FALSE), m_bRender(FALSE),
- m_bReadOnly(FALSE)
- {
- }
-
- CFlexWnd::~CFlexWnd()
- {
- Destroy();
- }
-
- void CFlexWnd::Destroy()
- {
- if (m_hWnd != NULL)
- DestroyWindow(m_hWnd);
-
- assert(m_privhWnd == NULL);
- }
-
- BOOL CFlexWnd::IsDialog()
- {
- return HasWnd() && m_bIsDialog;
- }
-
- void CFlexWnd::OnRender(BOOL bInternalCall)
- {
- // if parent is flexwnd and both are in render mode, pass to parent
- if (!m_hWnd)
- return;
- HWND hParent = GetParent(m_hWnd);
- if (!hParent)
- return;
- CFlexWnd *pParent = GetFlexWnd(hParent);
- if (!pParent)
- return;
- if (pParent->InRenderMode() && InRenderMode())
- pParent->OnRender(TRUE);
- }
-
- BOOL CFlexWnd::OnEraseBkgnd(HDC hDC)
- {
- if (InRenderMode())
- return TRUE;
-
- /* if (IsDialog())
- return FALSE;*/
-
- return TRUE;
- }
-
- struct GETFLEXWNDSTRUCT {
- int cbSize;
- BOOL bFlexWnd;
- CFlexWnd *pFlexWnd;
- };
-
- // This function takes a HWND and returns a pointer to CFlexWnd if the HWND is a window
- // created by the UI.
- CFlexWnd *CFlexWnd::GetFlexWnd(HWND hWnd)
- {
- if (hWnd == NULL)
- return NULL;
-
- GETFLEXWNDSTRUCT gfws;
- gfws.cbSize = sizeof(gfws);
- gfws.bFlexWnd = FALSE;
- gfws.pFlexWnd = NULL;
- SendMessage(hWnd, WM_GETFLEXWND, 0, (LPARAM)(LPVOID)(FAR GETFLEXWNDSTRUCT *)&gfws);
-
- if (gfws.bFlexWnd)
- return gfws.pFlexWnd;
- else
- return NULL;
- }
-
- // Basic window proc. It simply forward interesting messages to the appropriate handlers (OnXXX).
- // If child class defines this function, it should pass unhandled messages to CFlexWnd.
- LRESULT CFlexWnd::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch (msg)
- {
- case WM_GETFLEXWND:
- {
- if ((LPVOID)lParam == NULL)
- break;
-
- GETFLEXWNDSTRUCT &gfws = *((FAR GETFLEXWNDSTRUCT *)(LPVOID)lParam);
-
- switch (gfws.cbSize)
- {
- case sizeof(GETFLEXWNDSTRUCT):
- gfws.bFlexWnd = TRUE;
- gfws.pFlexWnd = this;
- return 0;
-
- default:
- assert(0);
- break;
- }
- break;
- }
-
- case WM_CREATE:
- {
- LPCREATESTRUCT lpCreateStruct = (LPCREATESTRUCT)lParam;
-
- LRESULT lr = OnCreate(lpCreateStruct);
-
- if (lr != -1)
- OnInit();
-
- return lr;
- }
-
- case WM_INITDIALOG:
- {
- BOOL b = OnInitDialog();
- OnInit();
- return b;
- }
-
- case WM_TIMER:
- OnTimer((UINT)wParam);
- return 0;
-
- case WM_ERASEBKGND:
- return OnEraseBkgnd((HDC)wParam);
-
- case WM_PAINT:
- {
- // Check the update rectangle. If we don't have it, exit immediately.
- if (typeid(*this) == typeid(CDeviceView) && !GetUpdateRect(m_hWnd, NULL, FALSE))
- return 0;
- PAINTSTRUCT ps;
- HDC hDC = BeginPaint(hWnd, &ps);
- if (InRenderMode())
- OnRender(TRUE);
- else
- DoOnPaint(hDC);
- EndPaint(hWnd, &ps);
- return 0;
- }
-
- case WM_COMMAND:
- {
- WORD wNotifyCode = HIWORD(wParam);
- WORD wID = LOWORD(wParam);
- HWND hWnd = (HWND)lParam;
- return OnCommand(wNotifyCode, wID, hWnd);
- }
-
- case WM_NOTIFY:
- return OnNotify(wParam, lParam);
-
- case WM_MOUSEMOVE:
- case WM_LBUTTONDOWN:
- case WM_RBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- case WM_MOUSEWHEEL:
- {
- POINT point = {int(LOWORD(lParam)), int(HIWORD(lParam))};
- switch (msg)
- {
- case WM_MOUSEMOVE: OnMouseOver(point, wParam); break;
- case WM_LBUTTONDOWN: OnClick(point, wParam, TRUE); break;
- case WM_RBUTTONDOWN: OnClick(point, wParam, FALSE); break;
- case WM_LBUTTONDBLCLK: OnDoubleClick(point, wParam, TRUE); break;
- case WM_MOUSEWHEEL:
- {
- // Send wheel msg to the window beneath the cursor
- HWND hWnd = WindowFromPoint(point);
- CFlexWnd *pWnd = NULL;
- if (hWnd)
- {
- pWnd = GetFlexWnd(hWnd);
- if (pWnd)
- pWnd->OnWheel(point, wParam);
- else
- return DefWindowProc(hWnd, msg, wParam, lParam);
- }
- break;
- }
- }
- return 0;
- }
-
- case WM_DESTROY:
- OnDestroy();
- m_privhWnd = NULL;
- return 0;
- }
-
- if (!m_bIsDialog)
- return DefWindowProc(hWnd, msg, wParam, lParam);
- else
- return 0;
- }
- static HMENU windex = 0;
-
- BOOL CFlexWnd::EndDialog(int n)
- {
- if (!m_bIsDialog || m_hWnd == NULL)
- {
- assert(0);
- return FALSE;
- }
-
- return ::EndDialog(m_hWnd, n);
- }
-
- int CFlexWnd::DoModal(HWND hParent, int nTemplate, HINSTANCE hInst)
- {
- return DoModal(hParent, MAKEINTRESOURCE(nTemplate), hInst);
- }
-
- HWND CFlexWnd::DoModeless(HWND hParent, int nTemplate, HINSTANCE hInst)
- {
- return DoModeless(hParent, MAKEINTRESOURCE(nTemplate), hInst);
- }
-
- int CFlexWnd::DoModal(HWND hParent, LPCTSTR lpTemplate, HINSTANCE hInst)
- {
- if (m_hWnd != NULL)
- {
- assert(0);
- return -1;
- }
-
- if (hInst == NULL)
- hInst = CFlexWnd::sm_hInstance;
-
- return (int)DialogBoxParam(hInst, lpTemplate, hParent,
- (DLGPROC)__BaseFlexWndDialogProc, (LPARAM)(void *)this);
- }
-
- HWND CFlexWnd::DoModeless(HWND hParent, LPCTSTR lpTemplate, HINSTANCE hInst)
- {
- if (m_hWnd != NULL)
- {
- assert(0);
- return NULL;
- }
-
- if (hInst == NULL)
- hInst = CFlexWnd::sm_hInstance;
-
- return CreateDialogParam(hInst, lpTemplate, hParent,
- (DLGPROC)__BaseFlexWndDialogProc, (LPARAM)(void *)this);
- }
-
- HWND CFlexWnd::Create(HWND hParent, const RECT &rect, BOOL bVisible)
- {
- ++(*(LPBYTE*)&windex);
- return Create(hParent, _T("(unnamed)"), 0,
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_EX_NOPARENTNOTIFY | (bVisible ? WS_VISIBLE : 0),
- rect, windex);
- }
-
- HWND CFlexWnd::Create(HWND hParent, LPCTSTR tszName, DWORD dwExStyle, DWORD dwStyle, const RECT &rect, HMENU hMenu)
- {
- HWND hWnd = NULL;
-
- if (m_hWnd != NULL)
- {
- assert(0);
- return hWnd;
- }
-
- if (hMenu == NULL && (dwStyle & WS_CHILD))
- {
- ++(*(LPBYTE*)&windex);
- hMenu = windex;
- }
-
- hWnd = CreateWindowEx(
- dwExStyle,
- CFlexWnd::sm_tszWndClassName,
- tszName,
- dwStyle,
- rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- hParent,
- hMenu,
- CFlexWnd::sm_hInstance,
- (void *)this);
-
- assert(m_hWnd == hWnd);
-
- return hWnd;
- }
-
- void CFlexWnd::SetHWND(HWND hWnd)
- {
- assert(m_hWnd == NULL && hWnd != NULL);
- m_privhWnd = hWnd;
- assert(m_hWnd == m_privhWnd);
-
- InitFlexWnd();
- }
-
- void CFlexWnd::InitFlexWnd()
- {
- if (!HasWnd())
- return;
-
- HWND hParent = GetParent(m_hWnd);
- CFlexWnd *pParent = GetFlexWnd(hParent);
- if (pParent && pParent->InRenderMode())
- SetRenderMode();
- }
-
- TCHAR sg_tszFlexWndPointerProp[] = _T("CFlexWnd *");
-
- LRESULT CALLBACK __BaseFlexWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- CFlexWnd *pThis = (CFlexWnd *)GetProp(hWnd, sg_tszFlexWndPointerProp);
-
- if ((msg == WM_MOUSEMOVE || msg == WM_MOUSEWHEEL) && hWnd != CFlexWnd::s_ToolTip.m_hWnd)
- {
- // Filter out the message with same window handle and point.
- // Windows sometimes seems to send us WM_MOUSEMOVE message even though the mouse is not moved.
- if (CFlexWnd::s_hWndLastMouseMove != hWnd || CFlexWnd::s_PointLastMouseMove != lParam)
- {
- CFlexWnd::s_hWndLastMouseMove = hWnd;
- CFlexWnd::s_PointLastMouseMove = lParam;
- CFlexWnd::s_dwLastMouseMove = GetTickCount(); // Get timestamp
- CFlexWnd::s_ToolTip.SetEnable(FALSE);
- CFlexWnd::s_ToolTip.SetToolTipParent(NULL);
- }
- }
-
- switch (msg)
- {
- case WM_CREATE:
- {
- LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
- if (lpcs == NULL)
- break;
-
- pThis = (CFlexWnd *)(void *)(lpcs->lpCreateParams);
- assert(sizeof(HANDLE) == sizeof(CFlexWnd *));
- SetProp(hWnd, sg_tszFlexWndPointerProp, (HANDLE)pThis);
-
- if (pThis != NULL)
- {
- pThis->m_bIsDialog = FALSE;
- pThis->SetHWND(hWnd);
- }
- break;
- }
- }
-
- if (pThis != NULL)
- return pThis->WndProc(hWnd, msg, wParam, lParam);
- else
- return DefWindowProc(hWnd, msg, wParam, lParam);
- }
-
- LRESULT CALLBACK __BaseFlexWndDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- CFlexWnd *pThis = (CFlexWnd *)GetProp(hWnd, sg_tszFlexWndPointerProp);
-
- switch (msg)
- {
- case WM_INITDIALOG:
- pThis = (CFlexWnd *)(void *)lParam;
- assert(sizeof(HANDLE) == sizeof(CFlexWnd *));
- SetProp(hWnd, sg_tszFlexWndPointerProp, (HANDLE)pThis);
- if (pThis != NULL)
- {
- pThis->m_bIsDialog = TRUE;
- pThis->SetHWND(hWnd);
- }
- break;
- }
-
- if (pThis != NULL)
- return (BOOL)pThis->WndProc(hWnd, msg, wParam, lParam);
- else
- return FALSE;
- }
-
- void CFlexWnd::Invalidate()
- {
- if (m_hWnd != NULL)
- InvalidateRect(m_hWnd, NULL, TRUE);
- }
-
- SIZE CFlexWnd::GetClientSize() const
- {
- RECT rect = {0, 0, 0, 0};
- if (m_hWnd != NULL)
- ::GetClientRect(m_hWnd, &rect);
- SIZE size = {
- rect.right - rect.left,
- rect.bottom - rect.top};
- return size;
- }
-
- void CFlexWnd::FillWndClass(HINSTANCE hInst)
- {
- sm_WndClass.cbSize = sizeof(WNDCLASSEX);
- sm_WndClass.style = CS_DBLCLKS;
- sm_WndClass.lpfnWndProc = __BaseFlexWndProc;
- sm_WndClass.cbClsExtra = 0;
- sm_WndClass.cbWndExtra = sizeof(CFlexWnd *);
- sm_WndClass.hInstance = sm_hInstance = hInst;
- sm_WndClass.hIcon = NULL;
- sm_WndClass.hCursor = NULL;
- sm_WndClass.hbrBackground = NULL;
- sm_WndClass.lpszMenuName = NULL;
- sm_WndClass.lpszClassName = sm_tszWndClassName;
- sm_WndClass.hIconSm = NULL;
- }
-
- void CFlexWnd::RegisterWndClass(HINSTANCE hInst)
- {
- if (hInst == NULL)
- {
- assert(0);
- return;
- }
-
- FillWndClass(hInst);
- RegisterClassEx(&sm_WndClass);
- sm_bWndClassRegistered = TRUE;
- }
-
- void CFlexWnd::UnregisterWndClass(HINSTANCE hInst)
- {
- if (hInst == NULL)
- return;
-
- UnregisterClass(sm_tszWndClassName, hInst);
- sm_bWndClassRegistered = FALSE;
- }
-
- void CFlexWnd::GetClientRect(LPRECT lprect) const
- {
- if (lprect == NULL || m_hWnd == NULL)
- return;
-
- ::GetClientRect(m_hWnd, lprect);
- }
-
- LPCTSTR CFlexWnd::GetDefaultClassName()
- {
- return CFlexWnd::sm_tszWndClassName;
- }
-
- void CFlexWnd::SetRenderMode(BOOL bRender)
- {
- if (bRender == m_bRender)
- return;
-
- m_bRender = bRender;
- Invalidate();
- }
-
- BOOL CFlexWnd::InRenderMode()
- {
- return m_bRender;
- }
-
- void EnumChildWindowsZDown(HWND hParent, WNDENUMPROC proc, LPARAM lParam)
- {
- if (hParent == NULL || proc == NULL)
- return;
-
- HWND hWnd = GetWindow(hParent, GW_CHILD);
-
- while (hWnd != NULL)
- {
- if (!proc(hWnd, lParam))
- break;
-
- hWnd = GetWindow(hWnd, GW_HWNDNEXT);
- }
- }
-
- void EnumSiblingsAbove(HWND hParent, WNDENUMPROC proc, LPARAM lParam)
- {
- if (hParent == NULL || proc == NULL)
- return;
-
- HWND hWnd = hParent;
-
- while (1)
- {
- hWnd = GetWindow(hWnd, GW_HWNDPREV);
-
- if (hWnd == NULL)
- break;
-
- if (!proc(hWnd, lParam))
- break;
- }
- }
-
- static BOOL CALLBACK RenderIntoClipChild(HWND hWnd, LPARAM lParam)
- {
- CFlexWnd *pThis = (CFlexWnd *)(LPVOID)lParam;
- return pThis->RenderIntoClipChild(hWnd);
- }
-
- static BOOL CALLBACK RenderIntoRenderChild(HWND hWnd, LPARAM lParam)
- {
- CFlexWnd *pThis = (CFlexWnd *)(LPVOID)lParam;
- // Check if this is the immediate child. Do nothing if it's not immediate.
- HWND hParent = GetParent(hWnd);
- if (hParent != pThis->m_hWnd)
- return TRUE;
- return pThis->RenderIntoRenderChild(hWnd);
- }
-
- BOOL CFlexWnd::RenderIntoClipChild(HWND hChild)
- {
- if (m_hRenderInto != NULL && HasWnd() && hChild && IsWindowVisible(hChild))
- {
- RECT rect;
- GetWindowRect(hChild, &rect);
- POINT ul = {rect.left, rect.top}, lr = {rect.right, rect.bottom};
- ScreenToClient(m_hWnd, &ul);
- ScreenToClient(m_hWnd, &lr);
- ExcludeClipRect(m_hRenderInto, ul.x, ul.y, lr.x, lr.y);
- }
- return TRUE;
- }
-
- BOOL CFlexWnd::RenderIntoRenderChild(HWND hChild)
- {
- CFlexWnd *pChild = GetFlexWnd(hChild);
- if (m_hRenderInto != NULL && HasWnd() && pChild != NULL && IsWindowVisible(hChild))
- {
- RECT rect;
- GetWindowRect(hChild, &rect);
- POINT ul = {rect.left, rect.top};
- ScreenToClient(m_hWnd, &ul);
- pChild->RenderInto(m_hRenderInto, ul.x, ul.y);
- }
- return TRUE;
- }
-
- void CFlexWnd::RenderInto(HDC hDC, int x, int y)
- {
- if (hDC == NULL)
- return;
-
- int sdc = SaveDC(hDC);
- {
- OffsetViewportOrgEx(hDC, x, y, NULL);
- SIZE size = GetClientSize();
- IntersectClipRect(hDC, 0, 0, size.cx, size.cy);
-
- m_hRenderInto = hDC;
-
- int sdc2 = SaveDC(hDC);
- {
- EnumChildWindows/*ZDown*/(m_hWnd, ::RenderIntoClipChild, (LPARAM)(PVOID)this);
- EnumSiblingsAbove(m_hWnd, ::RenderIntoClipChild, (LPARAM)(PVOID)this);
- DoOnPaint(hDC);
- }
- if (sdc2)
- RestoreDC(hDC, sdc2);
-
- EnumChildWindows/*ZDown*/(m_hWnd, ::RenderIntoRenderChild, (LPARAM)(PVOID)this);
-
- m_hRenderInto = NULL;
- }
-
- if (sdc)
- RestoreDC(hDC, sdc);
- }
-
- void CFlexWnd::SetCapture()
- {
- ::SetCapture(m_hWnd);
- }
-
- void CFlexWnd::ReleaseCapture()
- {
- ::ReleaseCapture();
- }
-
- void CFlexWnd::DoOnPaint(HDC hDC)
- {
- OnPaint(hDC);
- }
-